package handler

import (
	"fmt"
	"go-devops/common"
	"go-devops/domain/dto"
	"golang.org/x/crypto/ssh"
	"log"
	"time"
)

type SSHTaskHandler struct {
	CommonTaskHandler
}

func NewSSHTaskHandler() *SSHTaskHandler {
	return &SSHTaskHandler{
		CommonTaskHandler: CommonTaskHandler{},
	}
}

type SSHData struct {
	Command    string `json:"command"`
	Host       string `json:"host"`
	Port       int    `json:"port"`
	SecretName string `json:"secretName"`
	WorkDir    string `json:"workDir"`
}

func getSSHData(context *dto.NodeContext) SSHData {
	data := context.TaskData.Data
	jsonString := common.JsonString(data)
	var sshData SSHData
	common.ParseJson(jsonString, &sshData)
	return sshData
}

func (c SSHTaskHandler) Stop(context *dto.NodeContext) error {
	context.StopFlag = true
	context.Cancel()
	return nil
}

func (c SSHTaskHandler) HandleNode(nodeContext *dto.NodeContext) error {
	return c.Handle(nodeContext, func() error {
		workspace := nodeContext.Workspace
		log.Println("工作空间：" + workspace)
		sendMsg(nodeContext, true, fmt.Sprintf("工作空间：%s", workspace))

		data := getSSHData(nodeContext)
		log.Printf("SSHTaskHandler data:%+v\n", data)
		dataJson := common.JsonString(data)
		sendMsg(nodeContext, true, fmt.Sprintf("taskData:%s", dataJson))

		secret, err := GetSecret(common.SSH, data.SecretName)
		if err != nil {
			return err
		}
		log.Printf("SSHTaskHandler secret:+%v\n", secret)

		server := fmt.Sprintf("%s:%d", data.Host, data.Port)

		// 创建 SSH 客户端配置
		config := &ssh.ClientConfig{
			User: secret.SecretKey,
			Auth: []ssh.AuthMethod{
				ssh.Password(secret.SecretValue),
			},
			HostKeyCallback: ssh.InsecureIgnoreHostKey(),
		}

		// 连接到 SSH 服务器
		conn, err := ssh.Dial("tcp", server, config)
		if err != nil {
			log.Printf("Failed to dial: %v\n", err)
			return fmt.Errorf("ssh conn error: %v", err)
		}
		defer conn.Close()

		// 创建一个新的会话
		session, err := conn.NewSession()
		if err != nil {
			log.Printf("Failed to create session: %v\n", err)
			return fmt.Errorf("ssh create session error: %v", err)
		}
		defer session.Close()

		customWriter := &CustomWriter{
			Ctx: nodeContext,
		}

		session.Stdout = customWriter
		session.Stderr = customWriter

		// 启动命令
		sendMsg(nodeContext, true, "开始执行处理：--------------------------------------->")
		startTime := time.Now()

		command := data.Command

		if len(data.WorkDir) > 0 && data.WorkDir != "" {
			command = fmt.Sprintf("cd %s && %s", data.WorkDir, command)
		}

		// 执行命令
		err = session.Start(command)
		if err != nil {
			log.Printf("Failed to start ssh command: %v\n", err)
			return fmt.Errorf("ssh start command error: %v", err)
		}

		done := make(chan error, 1)
		go func() {
			done <- session.Wait()
		}()

		select {
		case <-nodeContext.Context.Done():
			// 超时或其他原因导致上下文关闭
			log.Println("Context canceled, terminating session...")
			session.Close()
			<-done // 等待会话关闭
			fmt.Println("Session terminated due to context cancellation.")
		case err := <-done:
			// 等待命令完成
			if err != nil {
				log.Printf("failed to wait ssh command: %v\n", err)
				return fmt.Errorf("ssh command finished with error: %w", err)
			}
		}

		endTime := time.Now() // 记录结束时间
		elapsedTime := endTime.Sub(startTime)
		sendMsg(nodeContext, true, "执行处理结束 <--------------------------------------- 耗时："+elapsedTime.String())
		return nil
	})
}
